#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Filename: lr_example.py

import numpy as np
from sklearn import linear_model, datasets
import matplotlib.pyplot as plt
from scipy.stats import norm
from scipy import fft
from scipy.io import wavfile

"""
n = 40
# hstack使得十足拼接
# rvs是Random Variates随机变量的意思
# 在模拟X的时候使用了两个正态分布,分别制定各自的均值,方差,生成40个点
X = np.hstack((norm.rvs(loc=2, size=n, scale=2), norm.rvs(loc=8, size=n, scale=3)))
# zeros使得数据点生成40个0,ones使得数据点生成40个1
y = np.hstack((np.zeros(n),np.ones(n)))
# 创建一个 10 * 4 点（point）的图，并设置分辨率为 80
plt.figure(figsize=(10, 4),dpi=80)
# 设置横轴的上下限
plt.xlim((-5, 20))
# scatter散点图
plt.scatter(X, y, c=y)
plt.xlabel("feature value")
plt.ylabel("class")
plt.grid(True, linestyle='-', color='0.75')
plt.savefig("D:/workspace/scikit-learn/logistic_classify.png", bbox_inches="tight")
"""

"""
# linspace是在-5到15的区间内找10个数
xs=np.linspace(-5,15,10)

#---linear regression----------
from sklearn.linear_model import LinearRegression
clf = LinearRegression()
# reshape重新把array变成了80行1列二维数组,符合机器学习多维线性回归格式
clf.fit(X.reshape(n * 2, 1), y)
def lin_model(clf, X):
    return clf.intercept_ + clf.coef_ * X

#---logistic regression--------
from sklearn.linear_model import LogisticRegression
logclf = LogisticRegression()
# reshape重新把array变成了80行1列二维数组,符合机器学习多维线性回归格式
logclf.fit(X.reshape(n * 2, 1), y)
def lr_model(clf, X):
    return 1.0 / (1.0 + np.exp(-(clf.intercept_ + clf.coef_ * X)))

#----plot---------------------------    
plt.figure(figsize=(10, 5))
# 创建一个一行两列子图的图像中第一个图
plt.subplot(1, 2, 1)
plt.scatter(X, y, c=y)
plt.plot(X, lin_model(clf, X),"o",color="orange")
plt.plot(xs, lin_model(clf, xs),"-",color="green")
plt.xlabel("feature value")
plt.ylabel("class")
plt.title("linear fit")
plt.grid(True, linestyle='-', color='0.75')
# 创建一个一行两列子图的图像中第二个图
plt.subplot(1, 2, 2)
plt.scatter(X, y, c=y)
plt.plot(X, lr_model(logclf, X).ravel(),"o",color="c")
plt.plot(xs, lr_model(logclf, xs).ravel(),"-",color="green")
plt.xlabel("feature value")
plt.ylabel("class")
plt.title("logistic fit")
plt.grid(True, linestyle='-', color='0.75')

plt.tight_layout(pad=0.4, w_pad=0, h_pad=1.0)     
plt.savefig("D:/workspace/scikit-learn/logistic_classify2.png", bbox_inches="tight")
"""

"""
使用logistic regression处理音乐数据,音乐数据训练样本的获得和使用快速傅里叶变换（FFT）预处理的方法需要事先准备好
1. 把训练集扩大到每类100个首歌而不是之前的10首歌,类别仍然是六类:jazz,classical,country, pop, rock, metal
2. 同时使用logistic回归和KNN作为分类器
3. 引入一些评价的标准来比较Logistic和KNN在测试集上的表现 
"""


# 准备音乐数据：创建傅里叶特征数据
def create_fft(song_cls, index):
    # 构造每个音乐文件的路径，zfill补全0到多少位
    sample_path = "d:/train_datas/" + song_cls + "/converted/" + song_cls + "." + str(index).zfill(5) + ".au.wav"
    # sample_rate：采样率；smaple：音乐文件数据
    sample_rate, smaple = wavfile.read(sample_path)
    # 把样本数据传递给傅里叶变换公式函数，并获取前1000Hz的数据，取绝对值
    fft_features = abs(fft(smaple)[:1000])
    fft_features_path = "d:/train_features/" + song_cls + "." + str(index).zfill(5) + ".fft"
    # 保存特征数据，结果文件的后缀会自动添加`.npy`的后缀
    np.save(fft_features_path, fft_features)


# -------create fft--------------
song_cls_list = ["classical", "jazz", "country", "pop", "rock", "metal"]
for song_cls in song_cls_list:
    for index in range(100):
        create_fft(song_cls, index)

# 构造训练集
# 加载训练集数据,分割训练集以及测试集,进行分类器的训练
# -------read fft--------------
song_cls_list = ["classical", "jazz", "country", "pop", "rock", "metal"]
X = []
Y = []
for song_cls in song_cls_list:
    for index in range(100):
        fft_features_path = "d:/train_features/" + song_cls + "." + str(index).zfill(5) + ".fft" + ".npy"
        fft_features = np.load(fft_features_path)
        X.append(fft_features)
        Y.append(song_cls_list.index(song_cls))

# 把list转化成numpy的数组
# X是一个二维数组，可以看做是一个矩阵；Y是一个一维数组
X = np.array(X)
Y = np.array(Y)
"""
# 首先我们要将原始数据分为训练集和测试集，这里是随机抽样80%做测试集，剩下20%做训练集 
import random
randomIndex=random.sample(range(len(Y)),int(len(Y)*8/10))
trainX=[];trainY=[];testX=[];testY=[]
for i in range(len(Y)):
    if i in randomIndex:
        trainX.append(X[i])
        trainY.append(Y[i])
    else:
        testX.append(X[i])
        testY.append(Y[i])
"""

# 接下来，我们使用sklearn，来构造和训练我们的两种分类器 
# ------train logistic classifier--------------
from sklearn.linear_model import LogisticRegression

# 默认情况下solver是libleaner，即解析解的方式
# solver使用的是梯度下降
model = LogisticRegression(multi_class="ovr", solver="sag", max_iter=10000)
model.fit(X, Y)
# predictYlogistic=map(lambda x:logclf.predict(x)[0],testX)

# 可以采用Python内建的持久性模型 pickle 来保存scikit的模型
"""
import pickle
s = pickle.dumps(clf) # 参数可以是一个模型即上面的model
clf2 = pickle.loads(s)
clf2.predict(X[0])
"""

"""
#----train knn classifier-----------------------
from sklearn.neighbors import NearestNeighbors
neigh = NearestNeighbors(n_neighbors=1)
neigh.fit(trainX) 
predictYknn=map(lambda x:trainY[neigh.kneighbors(x,return_distance=False)[0][0]],testX)

# 将predictYlogistic以及predictYknn与testY对比，我们就可以知道两者的判定正确率 
a = np.array(predictYlogistic)-np.array(testY)
print a, np.count_nonzero(a), len(a)
accuracyLogistic = 1-np.count_nonzero(a)/(len(a)*1.0)
b = np.array(predictYknn)-np.array(testY)
print b, np.count_nonzero(b), len(b)
accuracyKNN = 1-np.count_nonzero(b)/(len(b)*1.0)

print "%f" % (accuracyLogistic)
print "%f" % (accuracyKNN)
"""

print('Starting read wavfile...')
# prepare test data-------------------
sample_rate, test_sample = wavfile.read("d:/trainset/sample/heibao-wudizirong-remix.wav")
testdata_fft_features = abs(fft(test_sample))[:1000]
print(sample_rate, testdata_fft_features, len(testdata_fft_features))
# 获取概率最大的类别编号
cls_index = model.predict([testdata_fft_features])[0]
print("cls_index=\n", cls_index)
print("song_cls_list[cls_index]=\n", song_cls_list[cls_index])

"""
from sklearn.metrics import confusion_matrix
cmlogistic = confusion_matrix(testY, predictYlogistic)
cmknn = confusion_matrix(testY, predictYknn)

def plotCM(cm,title,colorbarOn,givenAX):
    ncm=cm/cm.max()
    plt.matshow(ncm, fignum=False, cmap='Blues', vmin=0, vmax=2.0)
    if givenAX=="":
        ax=plt.axes()
    else:
        ax = givenAX
    ax.set_xticks(range(len(song_cls_list)))
    ax.set_xticklabels(song_cls_list)
    ax.xaxis.set_ticks_position("bottom")
    ax.set_yticks(range(len(song_cls_list)))
    ax.set_yticklabels(song_cls_list)
    plt.title(title,size=12)
    if colorbarOn=="on":
        plt.colorbar()
    plt.xlabel('Predicted class')
    plt.ylabel('True class')
    for i in range(cm.shape[0]):
        for j in range(cm.shape[1]):
            plt.text(i,j,cm[i,j],size=15)

plt.figure(figsize=(10, 5))  
fig1=plt.subplot(1, 2, 1)          
plotCM(cmlogistic,"confusion matrix: FFT based logistic classifier","off",fig1.axes)   
fig2=plt.subplot(1, 2, 2)     
plotCM(cmknn,"confusion matrix: FFT based KNN classifier","off",fig2.axes) 
plt.tight_layout(pad=0.4, w_pad=0, h_pad=1.0)     

plt.savefig("d:/confusion_matrix.png", bbox_inches="tight")
"""
